import { pageData, sleep, Storage, transformQueryString } from '@/libs/utils';
import Vue from "vue";
import request from "../libs/request";
import { Response, RequestOptions } from './type';
import config, { local, online, path, page, authorizationValidPeriod } from "./config.json";

export const env: AnyObject = process.env.NODE_ENV === 'development' ? local : online;

export const $config: AnyObject = Object.assign(config, {
    API_URL: `http${env.isSecureProtocol ? "s" : ""}://${env.host}${env.port.api ? ":" + env.port.api : ""}${path.api_prefix || ""}`,
    SOCKET_URL: `ws${env.isSecureProtocol ? "s" : ""}://${env.host}${env.port.socket ? ":" + env.port.socket : ""}${path.socket || ""}`
});

const pretreatment: AnyObject = {
    throttle: false,
    times: 0,
    codeHandler: {
        "500": async ({ errmsg: title }: Response): Promise<string | void> => {
            if (pretreatment.throttle) return;
            pretreatment.throttle = true;

            if (page.authorization) {
                await uni.showToast({ title, icon: "none", duration: 1200 });
                pretreatment.throttle = true;
                await sleep(1.2)
                await uni.reLaunch({ url: page.authorization });
                pretreatment.throttle = false;

                return Promise.reject(title);
            }

            const authorization = Storage.get("authorization");

            if (authorization) {
                const [refreshFail, refreshRes]: any = await uni.request({
                    url: `${$config.API_URL}/refresh`,
                    header: { Authorization: authorization.refresh_token }
                });
                pretreatment.throttle = false;
                if (refreshFail) {
                    uni.showToast({ title: refreshFail.errMsg, icon: "none" });
                    return
                }

                const { errcode, errmsg: title, data } = refreshRes.data;
                if (errcode) {
                    uni.showToast({ title, icon: "none" });
                    return;
                }
                Storage.update("authorization", data, authorizationValidPeriod);

                const { route, options }: any = pageData(-1);
                uni.reLaunch({ url: `/${route}?${transformQueryString(options)}` });
                return Promise.reject(title);
            }

            const [loginFail, loginRes]: any = await uni.login({});
            if (loginFail) {
                uni.showToast({ title: loginFail.errMsg, icon: "none" });
                return Promise.reject(loginFail.errMsg);
            }

            const { code } = loginRes;
            const [reqFail, result]: any = await uni.request({
                url: `${$config.API_URL}${path.login_api}`,
                data: { code }
            });

            if (reqFail) {
                uni.showToast({ title: reqFail.errMsg, icon: "none" });
                return;
            }

            const { errcode, data, errmsg } = result.data;

            if (+errcode) {
                uni.showToast({ title: errmsg, icon: "none" });
                return;
            }

            Storage.set("authorization", data, authorizationValidPeriod);

            if (++pretreatment.times >= 3) {
                const [, modal]: any = await uni.showModal({
                    title: "prompt",
                    content: "Multiple redirects detected, Whether to continue?"
                });
                if (modal.cancel) return;
            }
            pretreatment.throttle = false;
            const { route, options }: any = pageData(-1);
            uni.reLaunch({ url: `/${route}?${transformQueryString(options)}` });
            return Promise.reject(title);

        },

        "0": (res: Response) => res,
        "-1": (res: Response) => res,

        "1": (res: Response) => {
            uni.showToast({ title: res.errmsg, icon: "none" });
            return Promise.reject(res)
        },

        "2": (res: Response) => Promise.reject(res),

        "3": (res: Response) => {
            const content = JSON.stringify(res, null, 2);
            uni.showModal({
                title: "Prompt",
                content,
                confirmText: "copy",
                cancelText: "i got it",
                success: ({ confirm }) =>
                    confirm && uni.setClipboardData({ data: content, success: () => uni.showToast({ title: "copied" }) })
            });
        },
    }
}

request.defaults.baseURL = $config.API_URL;

request.interceptors.request.use<RequestOptions>(
    params => {
        params.header.Authorization = Storage.get("authorization")?.access_token || "";

        for (const key in params.data) {
            if ([undefined, null, NaN].includes(params.data && params.data[key])) {
                delete params?.data[key];
            }
        }
        return params;
    }
);

request.interceptors.response.use<UniApp.RequestSuccessCallbackResult>(
    res => {
        const result = res.data as Response;

        try {
            if (Object.keys(pretreatment.codeHandler).includes(result.errcode.toString())) {
                return pretreatment.codeHandler[result.errcode.toString()](result)
            }

            uni.showToast({ title: "Server error, Please try again later.", icon: "none" });
            return Promise.reject(result);

        } catch ({ message: title }) {
            uni.showToast({ title, icon: "none" });
            return Promise.reject(title);
        } finally {
            console.warn(`Response:`, res);
        }
    },
    err => {
        uni.showToast({ title: err.errMsg, icon: "none" })
        return Promise.reject(err)
    }
);

Vue.prototype.$request = request;